package com.ibm.cps.api;

import java.util.ArrayList;
import java.util.Collection;

import javax.inject.Named;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo;

import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.ibm.cps.jarxs.PublisherResource;
import com.ibm.cps.message.MessageFields;
import com.ibm.cps.model.*;
import com.ibm.cps.test.PublishMonitor;
import com.ibm.factories.DataSourceFactory;
import com.ibm.factories.PublishProcessorFactory;
import com.ibm.interfaces.AbstractMessagePublisher;
import com.ibm.interfaces.IPersistency;
import com.ibm.mongo.MongoPersistency;
import com.ibm.util.ErrorCode;
import com.ibm.util.JSONUtility;
import com.ibm.util.exception.CPSException;

@Named
public class  PublisherBean implements PublisherResource{

	private PublisherMonitor pmonitor;
	private IPersistency persistency;
	private AuthorizationManager authManager;
	
	public PublisherBean() throws CPSException {
		persistency = MongoPersistency.getInstace();
		pmonitor = PublisherMonitor.getInstance();
		authManager = AuthorizationManager.getInstance();
	}
	
	@Override
	public Response GetPublishers(String tenantid, UriInfo info,String key) {
		if (!authManager.isAllow(tenantid, key)) {
			String ret = ServletUtil.constructReturnMsg(400, "invalid access");
			return Response.ok(ret,MediaType.APPLICATION_JSON).build();
		}
		
		ObjectNode filter = JSONUtility.newObjectNode(MessageFields.TENANTID,tenantid);
		MultivaluedMap<String, String> map = info.getQueryParameters();
		if (map.size() > 0) {
			for(String field : map.keySet()){
				filter.put(field, map.getFirst(field));
			}
		}
		
		try {
			PublishProcessorFactory publishFactory = PublisherMonitor.getInstance().getFactory(tenantid);
			DataSourceFactory factory = new DataSourceFactory();
			MetadataAdapter adapter = AdapaterFactory.getAdapter(factory, publishFactory, "rest");
			Collection<String> metadatas = persistency.getPublisher(filter);
			Collection<String> result = adapter.getJsons(metadatas, metadatas);
			String str = ServletUtil.constructCollectionJson(result);
			return Response.ok(str).type(MediaType.APPLICATION_JSON).build();
		} catch (CPSException e) {
			e.printStackTrace();
			ObjectNode node = JSONUtility.newObjectNode(MessageFields.STATUS_CODE, "400");
			node.put(MessageFields.RETURN_MESSAGE, e.getErrorMessage());
			return Response.ok(node.toString()).type(MediaType.APPLICATION_JSON).build();
		}

	}

	@Override
	public Response GetPublisher(String tenantid, String pub_name,String key) {
		if (!authManager.isAllow(tenantid, key)) {
			String ret = ServletUtil.constructReturnMsg(400, "invalid access");
			return Response.ok(ret,MediaType.APPLICATION_JSON).build();
		}
		
		try {
			PublishProcessorFactory publishFactory = PublisherMonitor.getInstance().getFactory(tenantid);
			DataSourceFactory factory = new DataSourceFactory();
			MetadataAdapter adapter = AdapaterFactory.getAdapter(factory, publishFactory, "rest");
			Collection<String> metadatas = persistency.getPublisher(tenantid,pub_name);
			Collection<String> result = adapter.getJsons(metadatas, metadatas);
			String str = ServletUtil.constructCollectionJson(result);
			return Response.ok(str).type(MediaType.APPLICATION_JSON).build();
		} catch (CPSException e) {
			ObjectNode node = JSONUtility.newObjectNode(MessageFields.STATUS_CODE, "400");
			node.put(MessageFields.RETURN_MESSAGE, e.getErrorMessage());
			return Response.ok(node.toString()).type(MediaType.APPLICATION_JSON).build();
		}

	
	}

	@Override
	public Response PutPublisher(String tenantid, String pub_name,String key) {
		if (!authManager.isAllow(tenantid, key)) {
			String ret = ServletUtil.constructReturnMsg(400, "invalid access");
			return Response.ok(ret,MediaType.APPLICATION_JSON).build();
		}
		
		ObjectNode node = JSONUtility.newObjectNode();
		node.put(MessageFields.STATUS_CODE, 400);
		node.put(MessageFields.RETURN_MESSAGE, "to be implemented");
		return Response.ok().entity(node.toString()).build();
	}
	
	@Override
	public Response PostPublisher(String tenantid, String json,String key) {
		if (!authManager.isAllow(tenantid, key)) {
			String ret = ServletUtil.constructReturnMsg(400, "invalid access");
			return Response.ok(ret,MediaType.APPLICATION_JSON).build();
		}
		
		ArrayList<AbstractMessagePublisher> persistObjects = new ArrayList<AbstractMessagePublisher>();
		try {
			ArrayNode array = JSONUtility.getArrayFromString(json);
			ArrayNode retArray = JSONUtility.newArrayNode();

			for (int i = 0; i < array.size(); i++) {
				ObjectNode objectNode = (ObjectNode) array.get(i);
				objectNode.put(MessageFields.TYPE, MessageFields.PUBLISHER_TYPE);
				objectNode.put(MessageFields.TENANTID, tenantid);
//				objectNode.put(MessageFields.SOURCE, source);
//				...
				AbstractMessagePublisher publisher = PublisherMonitor.getInstance().getFactory(tenantid).addPublishProcessor(objectNode.toString());
				ObjectNode retNode = JSONUtility.newObjectNode();
				retNode.put("id", publisher.getName());
				retArray.add(retNode);
				persistObjects.add(publisher);
			}

			for (int i = 0; i < persistObjects.size(); i++) {
				persistency.putPublisher(persistObjects.get(i).getProcessorMetadta());
			}
			String str =  ServletUtil.constructReturnMsg(ErrorCode.SUCCESS_CODE, retArray);
			return Response.ok(str).type(MediaType.APPLICATION_JSON).build();
		} catch (Throwable e) {
			try {
				for (int i = 0; i < persistObjects.size(); i++) {
					persistency.deletePublisher(tenantid, persistObjects.get(i).getName());
					pmonitor.getFactory(tenantid).deletePublishProcessor(persistObjects.get(i).getName(), tenantid);
				}
			} catch (CPSException e1) {
				e1.printStackTrace();

			}
			ObjectNode node = JSONUtility.newObjectNode(MessageFields.STATUS_CODE, "400");
			node.put(MessageFields.RETURN_MESSAGE, e.getMessage());
			return Response.ok(node.toString()).type(MediaType.APPLICATION_JSON).build();
		}
	}



	@Override
	public Response DeletePublishers(String tenantid,String key) {
		if (!authManager.isAllow(tenantid, key)) {
			String ret = ServletUtil.constructReturnMsg(400, "invalid access");
			return Response.ok(ret,MediaType.APPLICATION_JSON).build();
		}
		
		try {
			Collection<String> publishers = persistency.getPublisher(tenantid, null);
			Collection<String> deletedPublishers = new ArrayList<String>();
			if (publishers == null) {
				String str = ServletUtil.constructReturnMsg(ErrorCode.SUCCESS_CODE, "Nothing to be deleted");
				return Response.ok(str).type(MediaType.APPLICATION_JSON).build();
			}
			
			try {
				for (String pub : publishers) {
					AbstractMessagePublisher deleted = pmonitor.getFactory(tenantid)
							.deletePublishProcessor(JSONUtility.getString(MessageFields.NAME, pub), tenantid);
					persistency.deletePublisher(tenantid, deleted.getName());
					deletedPublishers.add(deleted.getProcessorMetadta());
				}
			} catch (Throwable e) {
				for (String del : deletedPublishers) {
					pmonitor.getFactory(tenantid).addPublishProcessor(del);
					persistency.putPublisher(del);
				}
				ObjectNode node = JSONUtility.newObjectNode(MessageFields.STATUS_CODE, "400");
				node.put(MessageFields.RETURN_MESSAGE, e.getMessage());
				return Response.ok(node.toString()).type(MediaType.APPLICATION_JSON).build();
			}
			String str =  ServletUtil.constructReturnMsg(ErrorCode.SUCCESS_CODE,ServletUtil.constructCollectionJson(publishers));
			return Response.ok(str).build();
		} catch (CPSException e) {
			e.printStackTrace();
			ObjectNode node = JSONUtility.newObjectNode(MessageFields.STATUS_CODE, "400");
			node.put(MessageFields.RETURN_MESSAGE, e.getMessage());
			return Response.ok(node.toString()).type(MediaType.APPLICATION_JSON).build();
		}
	
	}

	@Override
	public Response DeletePublisher(String tenantid, String pub_name,String key) {
		if (!authManager.isAllow(tenantid, key)) {
			String ret = ServletUtil.constructReturnMsg(400, "invalid access");
			return Response.ok(ret,MediaType.APPLICATION_JSON).build();
		}

		try {
			Collection<String> publishers = persistency.getPublisher(tenantid, pub_name);
			Collection<String> deletedPublishers = new ArrayList<String>();
			if (publishers == null) {
				String str = ServletUtil.constructReturnMsg(ErrorCode.SUCCESS_CODE, "Nothing to be deleted");
				return Response.ok(str).build();
			}
			
			try {
				for (String pub : publishers) {
					AbstractMessagePublisher deleted = pmonitor.getFactory(tenantid)
							.deletePublishProcessor(JSONUtility.getString(MessageFields.NAME, pub), tenantid);
					persistency.deletePublisher(tenantid, deleted.getName());
					deletedPublishers.add(deleted.getProcessorMetadta());
				}
			} catch (Throwable e) {
				for (String del : deletedPublishers) {
					pmonitor.getFactory(tenantid).addPublishProcessor(del);
					persistency.putPublisher(del);
				}
				ObjectNode node = JSONUtility.newObjectNode(MessageFields.STATUS_CODE, "400");
				node.put(MessageFields.RETURN_MESSAGE, e.getMessage());
				return Response.ok(node.toString()).type(MediaType.APPLICATION_JSON).build();
			}
			String str =  ServletUtil.constructReturnMsg(ErrorCode.SUCCESS_CODE,ServletUtil.constructCollectionJson(publishers));
			return Response.ok(str).type(MediaType.APPLICATION_JSON).build();
		} catch (CPSException e) {
			e.printStackTrace();
			String ret = ServletUtil.constructReturnMsg(e.getErrorCode(), e.getErrorMessage());
			return Response.ok(ret).type(MediaType.APPLICATION_JSON).build();
		}
	
	
	}



}
